package cn.adminsys.web.utils;

import cn.hutool.json.JSONUtil;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.profile.DefaultProfile;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * @author Emiya
 */
@Slf4j
public class AliyunOssStsUtil {

    public final static String ALI_OSS_STS_ACCESS_KEY_ID = "";
    public final static String ALI_OSS_STS_ACCESS_KEY_SECRET = "";
    public final static String ALI_OSS_STS_REGION_ID = "cn-beijing";
    public final static String ALI_OSS_STS_ROLE_ARN = "";
    public final static String ALI_OSS_STS_ROLE_SESSION_NAME = "OSS_STS_User";

    /**
     * 生成STS OSS上传临牌
     * @return
     */
    public static StsCredentials getStsAccessToken() {
        // ERROR: Code: NoPermission
        // Error message: You are not authorized to do this action. You should be authorized by RAM.
        // STS中临时授权访问OSS资源时出现报错的原因如下：
        // 原因一：代码中使用的AccessKey ID和AccessKeySecret是主账号的，并非RAM用户的。
        // 原因二：没有为RAM用户添加AliyunSTSAssumeRoleAccess权限策略。
        // 原因三：代码中使用的RoleARN参数对应的角色不是用户角色，而是服务角色。

        // 构建一个阿里云客户端，用于发起请求。
        // 构建阿里云客户端时需要设置AccessKey ID和AccessKey Secret。
        DefaultProfile profile = DefaultProfile.getProfile(ALI_OSS_STS_REGION_ID, ALI_OSS_STS_ACCESS_KEY_ID, ALI_OSS_STS_ACCESS_KEY_SECRET);
        IAcsClient client = new DefaultAcsClient(profile);

        //构造请求，设置参数。关于参数含义和设置方法，请参见《API参考》。
        AssumeRoleRequest request = new AssumeRoleRequest();
        request.setSysRegionId(ALI_OSS_STS_REGION_ID);
        request.setRoleArn(ALI_OSS_STS_ROLE_ARN);
        request.setRoleSessionName(ALI_OSS_STS_ROLE_SESSION_NAME);

        // 发起请求，并得到响应。
        try {
            AssumeRoleResponse response = client.getAcsResponse(request);
            String body = JSONUtil.toJsonStr(response);
            StsResponse sts = JSONUtil.toBean(body, StsResponse.class);
            if(sts != null && sts.getCredentials() != null) {
                return sts.getCredentials();
            }
        } catch (ServerException e) {
            log.info("ServerException: {} {} {}", e.getErrCode(), e.getErrMsg(), e.getRequestId());
        } catch (ClientException e) {
            log.info("ClientException: {} {} {}", e.getErrCode(), e.getErrMsg(), e.getRequestId());
        }
        return null;
    }

    @Data
    public static class StsResponse {
        private String requestId;
        private StsCredentials credentials;
        private StsAssumedRoleUser assumedRoleUser;
    }

    @Data
    public static class StsCredentials {
        private String accessKeyId;
        private String accessKeySecret;
        private String expiration;
        private String securityToken;
    }

    @Data
    public static class StsAssumedRoleUser {
        private String assumedRoleId;
        private String arn;
    }
}
